/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package do_.com.bpd.business.referrals.referralservermanager.impl;

import do_.bpd.hr.bank.referrals.api.ResultVO;
import com.google.gson.Gson;
import do_.bpd.hr.bank.referrals.api.InvalidReferral;
import do_.bpd.hr.bank.referrals.api.NonExistentReferral;
import do_.com.bpd.business.referrals.persistence.entities.*;
import do_.bpd.hr.bank.referrals.api.ReferralExistsAndActive;
import do_.bpd.hr.bank.referrals.api.VOReferral;
import do_.com.bpd.business.referrals.persistence.controllers.EntityChangeJpaController;
import do_.com.bpd.business.referrals.persistence.controllers.ReferralJpaController;
import do_.com.bpd.business.referrals.persistence.exceptions.NonexistentEntityException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import javax.persistence.Query;

/**
 *
 * @author Administrator
 */
public class ReferralManager implements IReferralManager {

    //<editor-fold defaultstate="collapsed" desc="Referral status constants">
    public static final String NEW_STATUS = "NEW";
    public static final String UNCONFIRMED = "UNCONFIR";//NC
    public static final String DELETED_STATUS = "DELETED";
    public static final String CAPTURED_STATUS = "CAPTURED";
    public static final String ISSUED_STATUS = "ISSUED";
    public static final String ACTIVATED_STATUS = "ACTIVATED";
    public static final String USED_STATUS = "USED";
    public static final String CLOSED_STATUS = "CLOSED";
    public static final String CANCELED_STATUS = "CANCELLED";
    public static final String UNDEFINED_STATUS = "UNDEFINED";
    public static final String APPROVED_STATUS = "APPROVED";//AP
    //</editor-fold>
    private static ReferralManager instance = null;
    private static String localLoggedUser = "";
    private ReferralJpaController rc;
    private Gson gson;

    public static ReferralManager getDefault(String loggedUser) {
        if (instance == null || (loggedUser == null ? localLoggedUser != null : !loggedUser.equals(localLoggedUser))) {
            localLoggedUser = loggedUser;
            instance = new ReferralManager();
        }
        System.out.println("Retorning instance of ReferralManager:" + instance);
        return instance;
    }

    private Gson getGson() {
        if (gson == null) {
            gson = new Gson();
        }
        return gson;
    }

    private ReferralJpaController getReferralController() {
        return new ReferralJpaController();
//        if (rc == null) {
//            rc = new ReferralJpaController();
//        }
//        return rc;
    }

    @Override
    public synchronized boolean cancelReferral(int referralId) {
        throw new UnsupportedOperationException(java.util.ResourceBundle.getBundle("do_/com/bpd/business/referrals/referralservermanager/bundle").getString("NOT SUPPORTED YET."));
    }

    //<editor-fold defaultstate="collapsed" desc="Create referral methods">
    @Override
    public synchronized Referral createReferral(Referral referral) {
        getReferralController().create(referral);
        return null;
    }

    //TODO AQUI
    private String checkClientIdFormat(String idClient) {
        String result = null;
        if (idClient != null) {
            result = idClient.replace("-", "");
            result = result.replace(".", "");
            result = result.replace("_", "");
            return result;
        }

        return "";
    }

    @Override
    public synchronized ResultVO createReferral(VOReferral referral) throws Exception {
        ResultVO result = new ResultVO();
        result.status = "insertado";

        boolean isValid = true;
//        String msg = "";
        Gson gsonx = getGson();
//        Referral rf = gson.fromJson(referral, Referral.class);
        Referral rf = new Referral();
        rf.setId(Integer.parseInt(referral.getId()));//TODO warning
//        System.out.println("referral.getReferralDate()==" + referral.getReferralDate());
        ///Dec 9, 2007 6:03:00 PM
        //String formatDate="Dec 9, 2007 6:03:00 PM";
        String formatDate = "MMM d, yyyy h:mm:ss a";
        //SimpleDateFormat
        Date tem = getDateFromString(referral.getReferralDate(), formatDate);

//        if (tem != null) {
//            System.out.println("date=" + tem.toString());
//        }

        rf.setReferralDate(tem);
        rf.setReferrerId(referral.getReferrerId());
        rf.setCustomerNtlId(checkClientIdFormat(referral.getCustomerNtlId()));
        rf.setLoggedUser(referral.getLoggedUser());

        if (rf == null) {
            throw new Exception("Invalid null referral.");
        }

        //Validate required info
        isValid = requiredInfoComplete(rf);

        //Validate if referrer is suspended
        isValid = referrerIsNotSuspended(rf.getReferrerId());

        //Validate if client is already in active referral
        isValid = clientIsReadyToRefer(rf);

        //Validate if source ip is forbidden
        isValid = ipIsInRange(rf.getSourceIp());

        //Validate if date is in the future
        isValid = isWithinDateRange(rf);

        if (!isValid) {
            result.status = "existe";
            return result;
        }

        probeStatusNull(rf);

        probeIdNull(rf);

        rf.setReferralCreationDate(new Date());

        rf.setTrackId(IdGen.generateId());

        //Arbitrarilly set the logged user
        rf.setLoggedUser(localLoggedUser);


        List<Referral> list = getReferralController().findEntitiesForField("Referral", "customerNtlId", rf.getCustomerNtlId(), "=");
        if ((list != null) && (list.size() > 0)) {
            result.status = "existe";
        } else {
            getReferralController().create(rf);
        }




//        Referral newReferral = getReferralController().findReferral(rf.getId());
//        String jsonReferral = gsonx.toJson(newReferral);
        return result;
    }

    @Override
    @Deprecated
    public Referral createReferral(Map<String, Object> options) throws InvalidReferral, ReferralExistsAndActive, Exception {
        ReferralJpaController rjc = getReferralController();
        Map<String, String> ecc;
        rjc.create(parseToReferral(options));
        return null;
    }
    //</editor-fold>

    @Override
    public boolean deleteReferral(Referral referral, String comment) {
        return deleteReferral(referral.getId(), comment);
    }

    @Override
    public boolean deleteReferral(int referralId, String comment) {
        authorize("ADMIN,OWNER,SYSTEM");

        boolean deleted = false;

        System.out.println("REFERRAL ID " + referralId);

        Referral referralFound = getReferralController().findReferral(referralId);
        if (referralFound != null) {
            String referralStatus = referralFound.getStatus();

            if (referralStatus == null) {
                referralStatus = ReferralManager.UNDEFINED_STATUS;
            }

            if (!referralStatus.equals(ReferralManager.DELETED_STATUS)) {
                String previousStatus = referralStatus;
                referralFound.setStatus(ReferralManager.DELETED_STATUS);
                try {
                    getReferralController().edit(referralFound);
                    deleted = true;
                    //Register incident
                    EntityChange ec = new EntityChange();
                    ec.setChangeDate(new Date());
                    ec.setCurrentValue(ReferralManager.DELETED_STATUS);
                    ec.setPreviousValue(previousStatus);
                    ec.setField("status");
                    ec.setEntityId(referralId);
                    ec.setEntityType("Referral");
                    ec.setComment(java.util.ResourceBundle.getBundle("do_/com/bpd/business/referrals/referralservermanager/bundle").getString("ENTITY DELETED BY ") + localLoggedUser);
                    ec.setId(0);

                    EntityChangeJpaController ecjc = new EntityChangeJpaController();
                    ecjc.create(ec);
                    ecjc = null;

                } catch (NonexistentEntityException ex) {
                    Logger.getLogger(ReferralManager.class.getName()).log(Level.SEVERE, null, ex);
                } catch (Exception ex) {
                    Logger.getLogger(ReferralManager.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }

        //Register change
        return deleted;
    }

    @Override
    public List<Referral> getEmployeeReferrals(String empId) {
        ReferralJpaController referralController = getReferralController();
        EntityManager entityManager = referralController.getEntityManager();

        String qStr = "SELECT r FROM Referral r WHERE r.referrerId = :referrerId";
        Query q = entityManager.createQuery(qStr);
        //Query createNamedQuery = entityManager.createNamedQuery("Referral.findByReferrerId");
        q.setParameter("referrerId", empId);
        //List resultList = q.getResultList();

        //Query q = getReferralController().getEntityManager().createNamedQuery("Referral.findByReferrerId");
        //Query setParameter = q.setParameter("referrer_id", empId);
        List<Referral> resultList = q.getResultList();
        return resultList;
    }

    @Override
    public boolean isClientReferralActive(String clientNtlId) throws Exception {
        throw new UnsupportedOperationException(java.util.ResourceBundle.getBundle("do_/com/bpd/business/referrals/referralservermanager/bundle").getString("NOT SUPPORTED YET."));
    }

    @Override
    public String normalizeNatlIdNumber(String natlId) {
        throw new UnsupportedOperationException(java.util.ResourceBundle.getBundle("do_/com/bpd/business/referrals/referralservermanager/bundle").getString("NOT SUPPORTED YET."));
    }

    @Override
    public Referral saveReferral(Referral referral, Map<String, Object> options) throws Exception {
        authorize("OWNER,ADMIN,SYSTEM");
        try {
            //VAlidate
            Referral ref = this.getAnyReferral(referral.getId());
            if (ref.getStatus().equals(DELETED_STATUS)) {
                throw new Exception(java.util.ResourceBundle.getBundle("do_/com/bpd/business/referrals/referralservermanager/bundle").getString("CANNOT MODIFY DELETED REFERRAL"));
            }
        } catch (do_.com.bpd.business.referrals.persistence.exceptions.NonExistentReferral ex) {
            Logger.getLogger(ReferralManager.class.getName()).log(Level.SEVERE, null, ex);
        }

        try {
            getReferralController().edit(referral);
        } catch (NonexistentEntityException ex) {
            Logger.getLogger(ReferralManager.class.getName()).log(Level.SEVERE, null, ex);
        } catch (Exception ex) {
            Logger.getLogger(ReferralManager.class.getName()).log(Level.SEVERE, null, ex);
        }
        return referral;
    }

    @Override
    public boolean transferReferral(int referralId, String transferTo, String comment) throws Exception {
        throw new UnsupportedOperationException(java.util.ResourceBundle.getBundle("do_/com/bpd/business/referrals/referralservermanager/bundle").getString("NOT SUPPORTED YET."));
    }

    @Override
    public List<Referral> findActiveReferrals() {
        throw new UnsupportedOperationException(java.util.ResourceBundle.getBundle("do_/com/bpd/business/referrals/referralservermanager/bundle").getString("NOT SUPPORTED YET."));
    }

    private Referral parseToReferral(Map<String, Object> options) {
        return null;
    }

    @Override
    public Referral getReferral(int referralId) throws NonExistentReferral {
        System.out.println("REFERRAL ID " + referralId);
        ReferralJpaController rjc = getReferralController();
        Referral findReferral = rjc.findReferral(referralId);
        if (null != findReferral) {
            if (findReferral.getStatus().equals(DELETED_STATUS)) {
                throw new NonExistentReferral(java.util.ResourceBundle.getBundle("do_/com/bpd/business/referrals/referralservermanager/bundle").getString("DELETED REFERRAL"));
            }
        }
        return findReferral;
    }

    public Referral getAnyReferral(int referralId) {
        authorize("ADMIN,SYSTEM");
        ReferralJpaController rjc = getReferralController();
        Referral findReferral = rjc.findReferral(referralId);
        return findReferral;
    }

    public String getReferral(String referralId) throws NonExistentReferral {
        System.out.println("before getReferral");
        Referral referral = getReferral(Integer.parseInt(referralId));
        System.out.println("after getReferral");
        return getGson().toJson(referral);
    }

    //<editor-fold defaultstate="collapsed" desc="Validations">
    private boolean requiredInfoComplete(Referral rf) {
        return true;
    }

    private boolean referrerIsNotSuspended(String referrerId) {
        return true;
    }

    private boolean clientIsReadyToRefer(Referral rf) {
        return true;
    }

    private boolean ipIsInRange(String sourceIp) {
        return true;
    }

    private boolean isWithinDateRange(Referral rf) {
        return true;
    }
    //</editor-fold>

    /**
     * Proxies to the Authorization Service
     * @param roles
     */
    private void authorize(String roles) {
        return;
    }

    /**
     * Lists all the referrals in the system
     * @return
     */
    public String getAllReferrals(String filter) {
        List<Referral> findReferralEntities = getReferralController().findReferralEntities();
        String toJson = getGson().toJson(findReferralEntities);
        return toJson;
    }

    /**
     * Lists all the referrals in the system
     * @return
     */
    public List<Referral> getAllReferrals() {
        List<Referral> findReferralEntities = getReferralController().findReferralEntities();
        return findReferralEntities;
    }

    /**
     * Lists all the active referrals in the system
     * @return
     */
    public List<Referral> getActiveReferrals() {
        EntityManager em = getReferralController().getEntityManager();
        Query q = em.createQuery("SELECT r FROM Referral r WHERE r.status <> '" + ReferralManager.DELETED_STATUS + "' AND r.status <> '" + ReferralManager.CLOSED_STATUS + "'");
        List<Referral> resultList = q.getResultList();
        return resultList;
    }

    private void probeStatusNull(Referral rf) {
        if (rf.getStatus() == null) {
            rf.setStatus(NEW_STATUS);
        }
        if (rf.getStatus().isEmpty()) {
            rf.setStatus(NEW_STATUS);
        }
    }

    private void probeIdNull(Referral rf) {
        if (rf.getId() == null) {
            rf.setId(0);
        }
    }

    public String changeStatus(int referralId, String newStatus) throws Exception {

        String statusChanged = "";

        if (newStatus == null) {
            throw new Exception("Null or blank status not allowed.");
        }

        try {
            final ReferralJpaController referralController = getReferralController();
            Referral rf = referralController.findReferral(referralId);
            rf.setStatus(newStatus);
            referralController.edit(rf);
            statusChanged = newStatus;
            return statusChanged;
        } catch (NonexistentEntityException ex) {
            Logger.getLogger(ReferralManager.class.getName()).log(Level.SEVERE, null, ex);
            throw new Exception("Error changing Referral status. " + ex.getMessage());
        } catch (Exception ex) {
            Logger.getLogger(ReferralManager.class.getName()).log(Level.SEVERE, null, ex);
            throw new Exception("Error changing Referral status. " + ex.getMessage());
        }
    }

    public String filterReferral(String filter) {
//        System.out.println("before Json");
        JSONFilter jFilter = getGson().fromJson(filter, JSONFilter.class);
        System.out.println("jFilter=" + filter);
        System.out.println("getKeyword=" + jFilter.getKeyword());
        System.out.println("getFilterType=" + jFilter.getFilterType());
        System.out.println("getDateSince=" + jFilter.getDateSince());
        System.out.println("getDateUntil=" + jFilter.getDateUntil());





//       
        String dateSince = null;
        String dateUntil = null;
        String formatDate = "MMM d, yyyy h:mm:ss a";
        String datefilter = "yyyy-MM-dd HH:mm:ss";//TODO si da problema el filtro aqui resolver en esta linea

        if (jFilter.getDateSince() != null) {
            Date temSince = getDateFromString(jFilter.getDateSince(), formatDate);
            dateSince = getDateStringFromDate(temSince, datefilter);
        }
        if (jFilter.getDateUntil() != null) {
            Date temUntil = getDateFromString(jFilter.getDateUntil(), formatDate);
            dateUntil = getDateStringFromDate(temUntil, datefilter);
        }

        List<Referral> findReferralEntities = getReferralController().findReferralEntitiesByFilter(jFilter.getKeyword(), jFilter.getFilterType(), dateSince, dateUntil);
        String toJson = getGson().toJson(findReferralEntities);
        return toJson;
    }
//public String OLDfilterReferral(String filter) {
////        System.out.println("before Json");
//        JSONFilter jFilter = getGson().fromJson(filter, JSONFilter.class);
////        System.out.println("jFilter=" + filter);
////        System.out.println("getKeyword=" + jFilter.getKeyword());
////        System.out.println("getFilterType=" + jFilter.getFilterType());
////        System.out.println("getDateSince=" + jFilter.getDateSince());
////        System.out.println("getDateUntil=" + jFilter.getDateUntil());
//        
//        
//        String datefilter = "yyyy-MM-dd HH:mm:ss";
//        String dateSince = getDateStringFromDate(jFilter.getDateSince(), datefilter);
//        String dateUntil = getDateStringFromDate(jFilter.getDateUntil(), datefilter);
//
//
//        List<Referral> findReferralEntities = getReferralController().findReferralEntitiesByFilter(jFilter.getKeyword(), jFilter.getFilterType(), dateSince, dateUntil);
//        String toJson = getGson().toJson(findReferralEntities);
//        return toJson;
//    }

    public static String getDateStringFromDate(Date date, String format) {
        SimpleDateFormat formatoDeFecha = null;
        if (date != null) {
            formatoDeFecha = new SimpleDateFormat(format);

            return formatoDeFecha.format(date);
        }
        return null;
    }

    public static Date getDateFromString(String date, String format) {
        Date fecha = null;
        try {
            SimpleDateFormat formatoDelTexto = new SimpleDateFormat(format);
            fecha = formatoDelTexto.parse(date);
        } catch (ParseException ex) {
            System.out.println("Error");
        }
        return fecha;
    }
}
